package com.example.article.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.api.entity.article.Article;
import com.example.api.entity.article.ArticlePraise;
import com.example.article.mapper.ArticlePraiseMapper;
import com.example.article.service.ArticlePraiseService;
import com.example.article.service.ArticleService;
import com.example.article.util.RedisClient;
import com.example.article.util.RedisLock;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import utils.AssertUtil;

import java.time.LocalDateTime;
import java.util.*;

/**
 * <p>
 * 点赞记录表 服务实现类
 * </p>
 *
 * @author lr
 * @since 2023-02-18
 */
@Service
@RequiredArgsConstructor
public class ArticlePraiseTServiceImpl extends ServiceImpl<ArticlePraiseMapper, ArticlePraise> implements ArticlePraiseService {

    private final RedisClient client;
    private final RedisLock lock;
    private final ArticlePraiseMapper articlePraiseMapper;
    private final ArticleService articleService;
    private static final String LIKED_KEY = "article:liked:";

    /**
     * 用户进行点赞
     *
     * @param articlePraise
     * @return
     */
    @Override
    public Object insert(ArticlePraise articlePraise) {
        // TODO: 2023/2/18  拿到当前登陆人信息
        //获取当前用户登录id
        final String userId = articlePraise.getUserId();
        //文章id
        String id = articlePraise.getId();
        final boolean locks = this.lock.lock(userId + id);
        if (locks) {
            try {
                //判断当前用户是否已给这篇文章点赞
                String key = LIKED_KEY + articlePraise.getPraiseUserId() + ":" + id;
                final Double zscore = client.zscore(key, userId);
                //文章信息
                final Article article = articleService.getBaseMapper().selectById(articlePraise.getId());
                Optional.ofNullable(article).orElseThrow(() -> new NullPointerException("该文章已被删除"));
                article.setUpdateTime(LocalDateTime.now());
                if (null == zscore) {
                    //不存在就可以进行点赞
                    article.setPraiseTotal(article.getPraiseTotal() + 1);
                    article.setUpdateTime(LocalDateTime.now());
                    final int result = articleService.getBaseMapper().updateById(article);
                    AssertUtil.isTrue(result == 0, "保存失败");
                    //保持到redis  key="id"  user="member"  System.currentTimeMillis()=score
                    client.zadd(key, userId, System.currentTimeMillis());
                    return null;
                }
                article.setPraiseTotal(article.getPraiseTotal() - 1);
                final int result = articleService.getBaseMapper().updateById(article);
                AssertUtil.isTrue(result == 0, "保存失败");
                client.zremove(key, userId);
            } finally {
                lock.unlock(userId + id);
            }

        }

        return null;
    }

    @Override
    public Object delete(int id) {
        return null;
    }

    @Override
    public Object update(ArticlePraise articlePraise) {
        return null;
    }

    /**
     * 去redis中查询top5的点赞用户
     * 解析出其中的用户id
     * 根据用户id去数据库查询用户
     *
     * @param id
     * @return
     */
    @Override
    public List load(int id) {
        String key = LIKED_KEY + id;
        //1.查询top5的点赞用户 zrange key 0 4
        Set<Object> top5 = client.range(key, 0L, 4L);
        if (top5 == null || top5.isEmpty()) {
            return Collections.emptyList();
        }
        //2.解析出其中的用户id
        final ArrayList<Object> ids = new ArrayList<>(top5);
        String idStr = StrUtil.join(",", ids);
        //3.根据用户id查询用户 WHERE id IN (5,1) ORDER BY FIELD(id,5,1)
        final List<Article> list = articleService.getBaseMapper().selectList(Wrappers.<Article>lambdaQuery().in(Article::getId, idStr).last("ORDER BY FIELD(id," + idStr + ")"));
        //.last("ORDER BY FIELD(id," + idStr + ")")
        return list;
    }

    @Override
    public List<Article> pageList() {
        // 根据用户查询
        final List<Article> articles = articleService.getBaseMapper().selectList(Wrappers.<Article>lambdaQuery().orderByDesc(Article::getPraiseTotal).last("limit 0,5"));
        articles.forEach(x -> {
            isBlogLiked(x);
        });
        return articles;
    }

    private void isBlogLiked(Article article) {
        // todo 其实这里需要拿到当前文章点赞的用户信息的
        final String id = article.getId();
        String key = "blog:liked:" + id;
        //拿到当前文章点赞的用户id
        Double score = client.zscore(key, article.getUserId());
        article.setContent(null != article.getUserId() && null != score ? String.valueOf(score) : null);
    }


}

